package com.tsfyun.common.base.util;

import cn.hutool.core.util.StrUtil;
import com.tsfyun.common.base.dto.UploadFileDTO;
import com.tsfyun.common.base.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.channels.FileChannel;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 文件工具类
 */
@Slf4j
public class FileUtil {

    public static UploadFileDTO wrapUploadFileDto(MultipartFile file, String fileType, String docId, String docType, String businessType, String memo) {
        return wrapUploadFileDto(file, fileType, docId, docType, businessType, memo,Boolean.FALSE);
    }
    public static UploadFileDTO wrapUploadFileDto(MultipartFile file, String fileType, String docId, String docType, String businessType, String memo,Boolean only) {
        UploadFileDTO uploadFileDTO = new UploadFileDTO();
        uploadFileDTO.setFile(file);
        uploadFileDTO.setFileType(fileType);
        uploadFileDTO.setDocId(docId);
        uploadFileDTO.setDocType(docType);
        uploadFileDTO.setBusinessType(businessType);
        uploadFileDTO.setMemo(memo);
        uploadFileDTO.setIsOnlyOne(only);
        return uploadFileDTO;
    }
    /**=
     * 复制文件
     * @param source
     * @param dest
     */
    public static void copyFileByNIO(File source, File dest) {
        if(dest != null && !dest.exists()){
            dest.getParentFile().mkdirs();
        }
        FileChannel inf = null;
        FileChannel out = null;
        FileInputStream inStream = null;
        FileOutputStream outStream = null;
        try {
            inStream = new FileInputStream(source);
            outStream = new FileOutputStream(dest);
            inf = inStream.getChannel();
            out = outStream.getChannel();
            inf.transferTo(0, inf.size(), out);
        } catch (IOException e) {
            log.error(StrUtil.format("复制文件异常,源文件【{}】",source.getName()),e);
        } finally {
            close(inStream);
            close(inf);
            close(outStream);
            close(out);
        }
    }
        /**
         * 关闭所有流
         * @param closeable
         */
        private static void close(Closeable closeable){
            if(closeable != null){
                try {
                    closeable.close();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }

        /**=
         * 压缩文件
         * @param zipFilePath
         * @param zipFile
         * @throws IOException
         */
        public static void execute(String zipFilePath,String zipFile) throws IOException {
            File file = new File(zipFilePath);
            if(file.exists()&&file.isDirectory()){
                File[] files = file.listFiles();
                InputStream input = null;
                ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(new File(zipFile)));
                for (int i = 0; i < files.length; ++i) {
                    input = new FileInputStream(files[i]);
                    zipOut.putNextEntry(new ZipEntry(files[i].getName()));
                    int temp = 0;
                    while ((temp = input.read()) != -1) {
                        zipOut.write(temp);
                    }
                    input.close();
                }
                zipOut.close();
            }else if(file.exists()&&file.isFile()){
                ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(new File(zipFile)));
                InputStream input = new FileInputStream(file);
                zipOut.putNextEntry(new ZipEntry(file.getName()));
                int temp = 0;
                while ((temp = input.read()) != -1) {
                    zipOut.write(temp);
                }
                input.close();
                zipOut.close();
            }
        }
        /**=
         * 删除目录及下所有文件
         * @param dir
         * @return
         */
        public static boolean deleteDir(File dir) {
            if (dir.isDirectory()) {
                String[] children = dir.list();
                //递归删除目录中的子目录下
                for (int i=0; i<children.length; i++) {
                    boolean success = deleteDir(new File(dir, children[i]));
                    if (!success) {
                        return false;
                    }
                }
            }
            // 目录此时为空，可以删除
            return dir.delete();
        }

    /**
     * 压缩目录成文件夹
     * @param sourceFilePath 目录
     * @param zipFileName    压缩文件名（不含文件后缀）
     */
    public static void fileToZip(String sourceFilePath,String zipFileName){
        File sourceFile = new File(sourceFilePath);
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        FileOutputStream fos = null;
        ZipOutputStream zos = null;

        if(sourceFile.exists() == false){
            throw new ServiceException(String.format("目录不存在【%s】",sourceFile.getName()));
        }else{
            try {
                File zipFile = new File(sourceFilePath + File.separator + zipFileName + ".zip");
                if(zipFile.exists()){
                    zipFile.delete();
                } else{
                    File[] sourceFiles = sourceFile.listFiles();
                    if(sourceFiles != null){
                        fos = new FileOutputStream(zipFile);
                        zos = new ZipOutputStream(new BufferedOutputStream(fos));
                        byte[] bufs = new byte[1024*10];
                        for(int i = 0;i< sourceFiles.length;i++){
                            //创建ZIP实体，并添加进压缩包
                            ZipEntry zipEntry = new ZipEntry(sourceFiles[i].getName());
                            zos.putNextEntry(zipEntry);
                            //读取待压缩的文件并写进压缩包里
                            fis = new FileInputStream(sourceFiles[i]);
                            bis = new BufferedInputStream(fis, 1024*10);
                            int read = 0;
                            while((read=bis.read(bufs, 0, 1024*10)) != -1){
                                zos.write(bufs,0,read);
                            }
                            //删除文件
                            sourceFiles[i].delete();
                        }
                    }
                }
            } catch (FileNotFoundException e) {
                log.error("文件不存在",e);
                throw new ServiceException("文件不存在");
            } catch (IOException e) {
                log.error("压缩文件异常",e);
                throw new ServiceException("压缩文件异常");
            } finally{
                //关闭流
                try {
                    if(null != bis) bis.close();
                    if(null != zos) zos.close();
                } catch (IOException e) {
                    log.error("关闭文件流异常",e);
                }
            }
        }
    }

    /**
     * 压缩文件并删除原文件
     * @param sourceFile
     * @param zipFileName   压缩文件名（不含文件后缀）
     */
    public static void fileToZipWithRemove(File sourceFile,String zipFileName){
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        FileOutputStream fos = null;
        ZipOutputStream zos = null;

        if(sourceFile.exists() == false){
           log.error(String.format("文件或目录不存在【%s】",sourceFile.getName()));
           throw new ServiceException(String.format("文件或目录不存在【%s】",sourceFile.getName()));
        }
        if(sourceFile.isDirectory()) { //目录
            fileToZip(sourceFile.getAbsolutePath(),zipFileName);
        } else {//文件
            byte[] bufs = new byte[1024*10];
            try {
                String parentPath = sourceFile.getParent();
                File zipFile = new File( parentPath+ File.separator + zipFileName + ".zip");
                fos = new FileOutputStream(zipFile);
                zos = new ZipOutputStream(new BufferedOutputStream(fos));
                if(zipFile.exists()){
                    zipFile.delete();
                }
                ZipEntry zipEntry = new ZipEntry(sourceFile.getName());
                zos.putNextEntry(zipEntry);
                //读取待压缩的文件并写进压缩包里
                fis = new FileInputStream(sourceFile);
                bis = new BufferedInputStream(fis, 1024 * 10);
                int read = 0;
                while ((read = bis.read(bufs, 0, 1024 * 10)) != -1) {
                    zos.write(bufs, 0, read);
                }
                bis.close();
                zos.close();
            } catch (FileNotFoundException e) {
                log.error("文件不存在",e);
                throw new ServiceException("文件不存在");
            } catch (IOException e) {
                log.error("压缩文件异常",e);
                throw new ServiceException("压缩文件异常");
            } finally{
                //关闭流
                try {
                    if(null != bis) bis.close();
                    if(null != zos) zos.close();
                } catch (IOException e) {
                    log.error("关闭文件流异常",e);
                }
            }
        }
    }

}


